/**
 * Function define, require, requirejs
 */
ninejs.extend(ninejs, function( exports ) {
	var define, require, requirejs;
	var head = document.getElementsByTagName('head')[0],
		loadingMap = {},
		factoryMap = {},
		modulesMap = {},
		scriptsMap = {},
		resMap = {},
		pkgMap = {};

	function appendScript( url, callback ) {
		if ( !(url in scriptsMap) ) {
			var script = document.createElement('script');

			scriptsMap[url] = true;
						
            if ( callback ) {
                if ( "onload" in script ) {
					script.onload = callback;
                } else {
					script.onreadystatechange = function() {
						if ( "loaded" == this.readyState || "complete" == this.readyState ) {
							callback();
						}
					};
				}
            }
			
			script.type = 'text/javascript';
			script.src = url;
			head.appendChild(script);

			return script;
		}
	}
    function loadScript( id, callback ) {
		id = require.formatId(id);

        var map = loadingMap[id] || (loadingMap[id] = []);
        map.push(callback);

        var res = resMap[id] || {},
			pkg = res.pkg,
			url = pkg ? pkgMap[pkg].url : (res.url || id);

        appendScript(url, callback);
    }
	function extend( target, src ) {
		for ( var prop in src ) {
			if ( src.hasOwnProperty(prop) ) {
				target[prop] = src[prop];
			}
		}
	}
	
	define = function( id, factory ) {
		id = require.formatId(id);
		factoryMap[id] = factory;
		
		var queue = loadingMap[id];
		if ( queue ) {
			for( var i = 0, len = queue.length; i < len; i++ ) {
				queue[i]();
			}
			delete loadingMap[id];
		}
	};
	require = function( names, callback ) {
		if ( typeof(names) == 'string' ) {
			names = [names];
		}

		var args = [], len = loadNum = names.length;		
		for ( var i = 0; i < len; i++ ) {
			(function( j ) {
				requirejs(names[j], function( data ) {
					args[j] = data;
					if ( 0 == --loadNum ) {
						callback.apply(this, args);
					}
				});
			})( i );
		}
	};
	requirejs = function( names, callback ) {
		var loadMap = {};
		var loadNum = 0;

		if ( typeof(names) == 'string' ) {
			names = [names];
		}
		
		for ( var i = 0, len = names.length; i < len; i++ ) {
			names[i] = require.alias(names[i]);
		}

		_loadjs(names);
		// _callFunc();

		function _loadjs( depArr ) {
			for ( var i = 0, len = depArr.length; i < len; i++ ) {
				var dep = depArr[i];
				if ( dep in factoryMap || dep in loadMap ) {
					continue;
				}
				loadMap[dep] = true;
				loadNum++;
				
				loadScript(dep, _callFunc);
				
				var child = resMap[dep];
				if ( child && 'deps' in child ) {
					_loadjs(child.deps);
				}
			}
		}
		function _callFunc() {
			if ( 0 == loadNum-- ) {
				var i, len, args = [];
				for ( i = 0, len = names.length; i < len; i++ ) {
					args[i] = require.getData(names[i]);
				}
				callback && callback.apply(this, args);
			}
		}
	};

	exports.extend(require, {
		getData: function( id ) {
			id = require.formatId(id);
			id = require.alias(id);
			
			var mod = modulesMap[id];
			if ( mod ) {
				return mod.exports;
			}

			var factory = factoryMap[id];
			if ( !factory ) {
				throw Error('Cannot find module `' + id + '`');
			}
			
			mod = modulesMap[id] = {
				'exports': {}
			};

			var ret = (typeof factory == 'function') ? factory.apply(mod, [mod]) : factory;
			if ( ret ) {
				mod.exports = ret;
			}

			return mod.exports;
		},
		resourceMap: function( obj ) {
			resMap = obj['res'] || {};
			pkgMap = obj['pkg'] || {};
		},
		alias: function( id ) {
			return id;
		},
		formatId: function( id ) {
			return id = id.indexOf('.js') > 0 ? id : (id + '.js');			
		}
	});

	exports.extend(exports, {
		define: define,
		require: require,
		requirejs: requirejs	
	});
});